iT邦幫忙

2026 iThome 鐵人賽

DAY 4
0
Kubernetes

探討k8s部署方式系列 第 4

多台後端伺服器會遇到狀況與解法[Day4]

  • 分享至 

  • xImage
  •  

二十五、多台 Backend 之後,為什麼常常需要 Redis?

當系統只有一台 Backend 時,很多資料暫時存在這台 Server 自己的記憶體裡,通常不會有太大問題。

例如:

Backend 1
├── Login Session
├── Cache
├── Temporary Data
└── Application Memory

因為所有 Request 都一定會進到同一台 Backend。

但是加入 Load Balancer 之後,架構變成:

                Load Balancer
                     │
          ┌──────────┼──────────┐
          ▼          ▼          ▼
      Backend 1  Backend 2  Backend 3

此時每一個 Request 都可能被分配到不同的 Backend。

這時就會出現一個重要問題:

Backend 1 的 Memory,Backend 2 是看不到的。

例如:

Backend 1 Memory
user_123 = logged_in

Backend 2 Memory
沒有 user_123

這表示只要系統把需要共享的資料存在單一 Backend 的記憶體中,就有可能產生不一致。

因此系統會需要一個所有 Backend 都可以共同存取的地方。

Redis 就經常扮演這個角色。


二十六、Redis 是什麼?

Redis 可以簡單理解成一個速度非常快的 Key-Value Database。

例如可以存:

"user:123:name" → "Tom"

或者:

"session:abc123" → user_id=123

Redis 最重要的特點之一,就是資料主要放在 Memory 中,因此讀寫速度非常快。

架構可以變成:

                Load Balancer
                     │
          ┌──────────┼──────────┐
          ▼          ▼          ▼
      Backend 1  Backend 2  Backend 3
          │          │          │
          └──────────┼──────────┘
                     │
                     ▼
                   Redis

這樣三台 Backend 都可以讀取相同的資料。


二十七、案例一:Session

假設使用者登入網站。

第一次 Request:

User
 │
 ▼
Load Balancer
 │
 ▼
Backend 1

Backend 1 驗證帳號密碼成功後,如果把登入狀態直接存在 Backend 1 的 Memory:

Backend 1

session_abc = {
    user_id: 123,
    logged_in: true
}

接著 Browser 帶著:

session_id = abc

發出下一個 Request。

但是這一次 Load Balancer 把 Request 分配給:

Backend 2

Backend 2 查自己的 Memory:

session_abc ?

結果發現:

不存在

於是 Backend 2 可能認為:

這個使用者沒有登入

這就產生了問題。

如果改成把 Session 存在 Redis:

Redis

session:abc
→ user_id = 123

那麼:

Backend 1 ─┐
Backend 2 ─┼──→ Redis
Backend 3 ─┘

不管 Request 被送到哪一台 Backend,都可以取得同一份 Session。

因此流程變成:

Browser
   │
   │ session_id=abc
   ▼
Load Balancer
   │
   ▼
Backend 2
   │
   │ GET session:abc
   ▼
Redis
   │
   ▼
user_id=123

Backend 2 就知道:

這個使用者已登入

二十八、但 JWT 不一定需要 Redis Session

這裡需要補充一點。

現在很多 API 使用 JWT Token 驗證,例如:

Authorization: Bearer eyJ...

JWT 本身就可以攜帶:

user_id
role
expiration

Backend 收到 Token 後,可以直接驗證簽章。

因此:

Backend 1
Backend 2
Backend 3

只要都使用相同的驗證 Key,就可以驗證同一個 JWT。

這種情況下:

登入驗證不一定需要把 Session 放進 Redis。

但 Redis 還是可能被用來處理:

Token Blacklist
Refresh Token
Logout State
Rate Limit
Temporary Authorization Data

所以 Redis 的用途不只 Session。


二十九、案例二:Cache

Redis 另一個非常常見的用途就是 Cache。

假設 API:

GET /api/products

每次都需要查 Database:

Backend
   │
   ▼
Database
   │
   ▼
SELECT * FROM products

如果這個 API 每秒有大量 Request:

Request 1 → DB
Request 2 → DB
Request 3 → DB
Request 4 → DB
Request 5 → DB

Database 就會承受大量查詢。

但商品資料可能五分鐘內根本不會改變。

這時就可以把查詢結果存進 Redis。

第一次 Request:

Backend
   │
   ▼
Redis
   │
   │ 沒有資料
   ▼
Database
   │
   ▼
取得 Product Data
   │
   ▼
Redis

例如:

products:list
→ JSON Data

並設定:

TTL = 300 seconds

接下來其他 Request:

Backend
   │
   ▼
Redis
   │
   ▼
Product Data

就不用再次查 Database。

因此從:

Request
   │
   ▼
Database

變成:

Request
   │
   ▼
Redis

只有 Cache Miss 的時候才查 Database。


三十、為什麼多台 Backend 更需要集中式 Cache?

假設沒有 Redis,而是每台 Backend 自己做 Memory Cache:

Backend 1
cache:
product_1 = $100

Backend 2
cache:
product_1 = $100

Backend 3
cache:
product_1 = $100

這看起來好像沒有問題。

但是今天商品價格變成:

$120

Backend 1 更新了自己的 Cache:

Backend 1
product_1 = $120

Backend 2、Backend 3 卻可能還是:

product_1 = $100

於是:

Request 1 → Backend 1 → $120
Request 2 → Backend 2 → $100
Request 3 → Backend 3 → $100

使用者可能會看到不同結果。

如果三台 Backend 都使用同一個 Redis:

                     Redis

             product_1 = $120

              ▲       ▲       ▲
              │       │       │
         Backend 1 Backend 2 Backend 3

Cache 就能集中管理。


三十一、案例三:Rate Limiting

Redis 也常被拿來做 API Rate Limit。

例如規定:

同一個 IP
1 分鐘最多 100 次 Request

如果只有一台 Backend,可以直接在 Backend Memory 裡計數:

192.168.1.10 = 30 requests

但如果有三台 Backend:

Backend 1 → 30
Backend 2 → 20
Backend 3 → 25

每台都只知道自己收到多少 Request。

實際上使用者已經發了:

30 + 20 + 25 = 75

但沒有任何一台 Backend 知道總數。

如果使用 Redis:

rate_limit:192.168.1.10
→ 75

每台 Backend 都更新同一個 Counter:

Backend 1 ─┐
Backend 2 ─┼── INCR → Redis
Backend 3 ─┘

這樣才能正確計算整體 Request 數量。


三十二、案例四:Distributed Lock

多台 Backend 還會碰到另一個問題:

同一個工作可能被執行很多次。

例如系統有一個排程:

每天凌晨 01:00
同步第三方訂單

現在有三台 Backend:

Backend 1
Backend 2
Backend 3

如果每一台都啟動 Scheduler:

01:00

Backend 1 → 執行同步
Backend 2 → 執行同步
Backend 3 → 執行同步

同一個工作就會被執行三次。

可能造成:

重複建立資料
重複寄 Email
重複扣庫存
重複呼叫第三方 API

因此需要一種機制:

三台 Backend 裡
只能有一台取得執行權

這就是 Distributed Lock。

Redis 可以建立一個 Lock:

job:sync_order:lock

例如 Backend 1 先取得:

SET job:sync_order:lock backend1 NX EX 300

表示:

如果 Key 不存在
才建立 Lock

300 秒後自動過期

此時:

Backend 1 → Lock 成功 → 執行工作

Backend 2 → Lock 失敗 → 不執行

Backend 3 → Lock 失敗 → 不執行

架構就是:

                Redis Lock
                    │
          ┌─────────┼─────────┐
          │         │         │
          ▼         ▼         ▼
     Backend 1  Backend 2  Backend 3
        ✓          X          X

這就是 Redis 在多台 Backend 架構中非常常見的一種用途。


三十三、Redis 還可以存哪些資料?

Redis 常見用途包括:

Session
Cache
Rate Limit
Distributed Lock
OTP
Verification Code
Temporary Token
Shopping Cart
Queue
Realtime Counter

例如驗證碼:

otp:0912345678
→ 738291

TTL = 300 seconds

五分鐘後 Redis 自動刪除。

這種「有時效性的暫存資料」非常適合 Redis。


三十四、Redis 跟 Database 有什麼差別?

這裡也需要避免一個常見誤解:

Redis 通常不是拿來完全取代 MySQL。

MySQL 負責的是主要的永久資料,例如:

User
Order
Product
Payment
Booking

Redis 通常負責的是:

Cache
Session
Temporary Data
Shared State
Lock
Counter

架構可以理解成:

                   Backend
                      │
             ┌────────┴────────┐
             │                 │
             ▼                 ▼
           Redis             MySQL
             │                 │
             │                 │
      快速 / 暫存資料      正式持久資料

例如商品資料真正的來源還是 MySQL:

MySQL

product_id = 1
price = 120

Redis 只是保存一份 Cache:

Redis

product:1
price = 120
TTL = 300

如果 Redis 的 Cache 消失,通常還可以重新向 MySQL 查詢並建立 Cache。


三十五、多台 Backend 的完整架構

加入 Redis 後,前面的架構就會從:

                Load Balancer
                     │
          ┌──────────┼──────────┐
          ▼          ▼          ▼
      Backend 1  Backend 2  Backend 3
                     │
                     ▼
                  Database

變成:

                       Load Balancer
                            │
                 ┌──────────┼──────────┐
                 ▼          ▼          ▼
             Backend 1  Backend 2  Backend 3
                 │          │          │
                 └─────┬────┴────┬─────┘
                       │         │
                       ▼         ▼
                     Redis     Database

兩者負責不同工作:

Redis
├── Cache
├── Session
├── Lock
├── Counter
└── Temporary Data

Database
├── User
├── Product
├── Order
├── Payment
└── Business Data

所以 Redis 真正解決的是:

多台 Backend 彼此獨立,但某些狀態卻需要共享的問題。

換句話說:

Backend 不應該依賴
「只有自己知道的 Memory 狀態」

而應該盡可能設計成:

Backend 1
Backend 2
Backend 3

任何一台收到 Request
都可以正確處理

這種 Backend 也常被稱為:

Stateless Backend。

而 Redis、Database 等外部服務,則負責保存真正需要共享的 State。

這也是系統要從單台 Backend 走向水平擴充時,一個非常重要的架構觀念。


上一篇
負載平衡[Day3]
下一篇
從快取延伸至無狀態後端[Day5]
系列文
探討k8s部署方式9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言